1.清除浮动
浮动的元素会影响其兄弟元素的位置,并可能导致父元素的高度塌陷(假如父元素没设置高度),因此需要清除浮动(带来的影响)。
1.1 方法
常用方法有:
- 给浮动元素的父元素一个固定高度(不推荐)
- 给浮动元素新增一个空的
div
兄弟元素,设置clear:both
- 给浮动元素新增一个
<br>
兄弟元素,设置 clear 属性为 all - 给浮动元素的父元素新增一个 after 伪类,设置该伪类和父元素:
div{
zoom:1;
}
div:after{
content:"";
display:block;
clear:both;
}
- 给浮动元素的父元素设置
display: table
(触发BFC) - 给浮动元素的父元素也设置浮动(触发 BFC。不推荐)
- 给浮动元素的父元素设置
overflow: hidden
(触发 BFC)
1.2 原理
这里主要说下 clear:both
。clear:both
意思是说,设置了该属性的元素,其左边和右边不允许存在浮动元素。
- 父元素高度塌陷的情况:子元素浮动后脱离了文档流,未设置高度的父元素在形式上表现为 0 高度,设置了
clear:both
的元素为了满足其左右两边没有浮动元素的这个条件,只能自身下移,从而带动了父元素高度的撑开。 - 兄弟元素覆盖的情况:同理,比如A由于浮动覆盖了 C,我们在 AC 之间新增一个 B 元素,则 BC 位于同一文档流,B 为了满足其左右两边没有浮动元素的这个条件,只能自身下移,从而带动了 C 元素向下移动直到没有被 A 覆盖。
那么为什么除了 clear:both
之外,其他方法也能清除浮动呢?因为那些方法大都触发了 BFC,而 BFC 是可以清除浮动的,这个后面再介绍。
2.margin 塌陷
文档流内,块级元素与块级元素在垂直方向上的 margin 有时会合并(塌陷)为单个 margin,这样的现象称之为 margin 塌陷(margin collapse)。具体包括三种情况:
相邻的兄弟元素之间:
原因:
相邻的兄弟元素默认位于同一个块级上下文中
计算规则:
正正取大值,正负值相加,负负最小值父元素与第一个/最后一个子元素之间:
原因:
a.margin-top 重叠
父元素非块状格式化上下文元素
父元素没有border-top设置
父元素没有padding-top值
父元素和第一个子元素之间没有inline元素分隔
b.margin-bottom 重叠
父元素非块状格式化上下文设置
父元素没有border-bottom
设置
父元素没有padding-bottom
值
父元素和第一个子元素之间没有inline元素分隔
父元素没有 height,min-height,max-height
计算规则:
子元素和父元素上边界重叠,并且以子元素的margin-top
作为父元素的margin-top
整体移动。对于margin-bottom
同理。空的block元素:
原因:
元素没有 border 设置
元素没有 padding 值
里面没有 inline 元素
没有 height 或者min-height
那么怎么解决 margin 塌陷问题呢?同样是利用接下来要讲到的 BFC。
3.BFC
3.1 什么是 BFC?
BFC 即 Block formatting context,译为块级格式化上下文。简单来说,它是一种属性,这种属性影响着元素的定位以及与其兄弟元素之间的相互作用。因为是属性,所以我们通常说“元素具有 BFC”、“元素触发了 BFC”,而不说“元素是 BFC”。
从样式上看,具有 BFC 的元素与普通的容器没有什么区别;但是从功能上,具有 BFC 的元素可以看作是隔离了的独立容器,容器里面的子元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器没有的一些特性。
3.2 如何触发 BFC?
CSS 规定满足下列 CSS 声明之一的元素便会生成 BFC:
- 根元素或其它包含它的元素;
- float 的值不为 none;
- overflow 的值不为 visible;
- position 的值为 absolute 或 fixed;
- display 的值为 inline-block、table-cell、table-caption、table、flex、inline-flex、flow-root
table 本身不生成 BFC,而是 table 默认生成的匿名 table-cell 会生成 BFC
3.3 BFC 的特性
从整体上看,BFC 是隔离了的容器,这个具体可以表现为三个特性:
3.3.1 BFC 会阻止 margin 塌陷
前面我们说过 BFC 可以用于解决 margin 塌陷问题。
- 因为相邻兄弟元素默认位于同一个 BFC 是导致 margin 塌陷的原因,所以我们只需要设法隔离它们两者即可 ———— 假设有兄弟元素 A 和 B,可以使 A 的父元素触发 BFC,此时,触发了 BFC 的父元素里面的 A 子元素不会在布局上影响到 B,也自然不会有 margin 的叠加。
- 同样地,如果是父子嵌套的 margin 塌陷问题,只需要触发父元素的 BFC 即可。
3.3.2 BFC 可以包含浮动的元素
前面说过,父元素没有设置高度时,子元素的浮动会导致父元素表现为 0 高度,也就是说正常情况下父元素无法包含浮动的子元素。如图:
.Fa{
border: 2px solid red;
width: 300px;
}
.son{
width:180px;
height:180px;
background-color:yellow;
float:left;
}
但是触发了父元素的 BFC 后,父元素将可以包含浮动的子元素。如图:
.Fa{
border: 2px solid red;
width: 300px;
overflow:hidden; /* 随便一个 BFC 的触发条件 */
}
.son{
width:180px;
height:180px;
background-color:yellow;
float:left;
}
3.3.3 BFC 可以阻止元素被浮动元素覆盖
前面说过浮动元素会影响兄弟元素的位置,具体地说就是浮动之后脱离了文档流,使得兄弟元素上移填补空缺,而这会使得它被浮动元素覆盖。如图:
但是触发了兄弟元素的 BFC 后,它将不会被浮动的元素覆盖 —— 不会被覆盖,意味着兄弟元素出现在浮动元素的旁边或者下面,具体取决于父元素的宽度。
如果父元素的宽度足以包含这两个子元素的宽度之和,则子兄弟元素和子浮动元素并排。如图(这实际上就是两列布局的一种实现方式):
如果父元素的宽度不足以包含这两个子元素的宽度之和,则子兄弟元素会出现在子浮动元素的下面。如图:
4.可视化格式模型
让我们进一步拓展一下可视化格式模型的一些概念,由于比较复杂,所以只做了解即可。
可视化格式模型规定了客户端(浏览器)如何在媒介(显示器)中渲染文档树(document tree)。如下图,每个节点、元素都有属于自己的可见或不可见、有名或匿名的盒模型,可视化格式模型即规定了这些盒、框框如何整齐地排列在页面中,还有盒子之间的相互作用。
可视化格式模型的体系包括:
1.包含块 CB(Containing block)
2.控制框:块框、行框
3.FC(Formatting Context, 格式化上下文)
- BFC(Block Formatting Context, 块级格式化上下文)
- IFC(Inline Formatting Context, 行内格式上下文)
- GFC(Grid Formatting Context, 网格布局格式化上下文)
- FFC(Flex formatting contexts, 自适应格式上下文)
4.定位体系/方案(普通流、定位流、浮动流)
5.浮动体系
这里只说 FC 和定位体系。
4.1 FC
FC 即 Formatting context,译为格式化上下文。这是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系、相互作用。除了最常见的 CSS2.1 中的 BFC 和 IFC 之外,CSS3 中还增加了 GFC 和 FFC。
4.1.1 BFC:
前面已经说过了。
4.1.2 IFC:
- IFC 的 line box 高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的 padding/margin 影响)。IFC 的line box 一般左右都贴紧整个 IFC,但是会因为 float 元素而扰乱。float 元素会位于 IFC 与 line box 之间,使得 line box 宽度缩短。 同个 IFC 下的多个 line box 高度会不同。
- IFC 中是不可能有块级元素的,当插入块级元素时(如
p
中插入div
)会产生两个匿名块与div
分隔开,即产生两个 IFC,每个 IFC 对外表现为块级元素,与div
垂直排列。 - 那么IFC一般有什么用呢?
水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生 IFC,通过 text-align 则可以使其水平居中。
垂直居中:创建一个 IFC,用其中一个元素撑开父元素的高度,然后设置其vertical-align:middle
,其他行内元素则可以在此父元素下垂直居中。
4.1.3 GFC:
- 当为一个元素设置
display:grid
的时候,此元素将会获得一个独立的渲染区域,我们可以通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间。 - 那么 GFC 有什么用呢,和 table 又有什么区别呢?首先同样是一个二维的表格,但 GridLayout 会有更加丰富的属性来控制行列,控制对齐以及更为精细的渲染语义和控制。
4.1.4 FFC:
display:flex
或者 display:inline-flex
的元素将会生成自适应容器(flex container),可惜这个牛逼的属性只有谷歌和火狐支持,不过在移动端也足够了,至少 safari 和 chrome 还是 OK 的,毕竟这俩在移动端才是王道。
Flex box 由伸缩容器和伸缩项目组成。通过设置元素display:flex
或者 display:inline-flex
可以得到一个伸缩容器。设置为 flex 的容器被渲染为一个块级元素,而设置为 inline-flex 的容器则渲染为一个行内元素。
伸缩容器中的每一个子元素都是一个伸缩项目。伸缩项目可以是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说,Flex box 定义了伸缩容器内伸缩项目该如何布局。
4.2 定位方案
在定位的时候,浏览器会根据元素的盒类型和上下文对这些元素进行定位,可以说盒就是定位的基本单位。在 CSS2.1 中,有三种定位方案 ———— 普通流、浮动和绝对定位,下面分别对这三种布局简略说明一下:
普通流(Normal flow)
- 在普通流中,盒一个接着一个排列;
- 在块级格式化上下文里面,它们竖着排列;
- 在行内格式化上下文里面,它们横着排列;
- 通常情况下, position 为 static 或 relative,并且 float 为 none ,因而会触发普通流;
- position 为 static 时,盒的位置是常规流布局里的位置;
- position 为 relative 时,盒偏移位置由 top,bottom,left 和 right 定义。即使有偏移,仍然保留原有的位置,其它普通流不能占用这个位置。
浮动 (Floats)
- 元素脱离普通流,并且影响普通流的布局 ———— 导致普通流环绕在它的周边,除非设置 clear 属性;
- 盒称为浮动盒(floating boxes);
- 它位于当前行的开头或末尾;
绝对定位 (Absolute positioning)
- 元素脱离普通流,并且不影响普通流的布局
- 它的定位相对于它的包含块,相关CSS属性:top,bottom,left 和 right;
- 如果元素为
position:absolute
或position:fixed
,它是绝对定位元素; - 对于
position: absolute
,元素将相对最近的一个非 static 定位的父元素进行定位,如果没有则相对于 body;